﻿//Description:排产定时任务处理类
//Copyright (c) : 通力凯顿（北京）系统集成有限公司
//Writer:Wangjh
//create Date:2023-8-9
//Rewriter:zhangrj
//Rewrite Date:2023-10-31
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
using DatabaseAccess.DBUtility;
using BusinessRule.Business;
using System.Collections;
using BusinessRule.Common;
using System.Collections.Concurrent;
using System.Threading.Tasks;
using System.Configuration;
using System.Threading;

namespace MESScheduledTask
{
    public class ApsScheduledTaskBusiness
    {
        private LimitedCapacityBusiness m_LMObj = new LimitedCapacityBusiness();
        public static readonly int maxParallelSync = Convert.ToInt32(ConfigurationManager.AppSettings["maxParallelSync"].ToString());//最大并行任务数

        /// <summary>
        /// 测试
        /// </summary>
        /// <param name="dr"></param>
        /// <param name="apsTempTable"></param>
        void DealSingleApsTaskTest(DataRow dr, String apsTempTable) {

            for (int i = 0; i < 5; i++)
            {
                //检查是否提前终止
                if (DatabaseHelper.GetSingle(string.Format(@"select 1 from ScheduledTaskLogs sl
                            where sl.scheduledtaskid='{0}' and sl.islatest=1 and sl.taskexeendtime is not null", dr["ScheduledTaskId"].ToString())) != null)
                {
                    LogHelp.WriteLog("任务：" + dr["taskname"].ToString() + " " + dr["taskdesc"].ToString() + " 执行完毕----------------------------------------------------------------------");
                    return;
                }
                //m_LMObj.TestApsTempTable(apsTempTable, dr["taskdesc"].ToString());
            }

            //此任务执行完毕
            CommonHelper.WriteTaskLog(dr["ScheduledTaskId"].ToString(), "4", " 任务执行完毕，", "1");
            LogHelp.WriteLog("任务：" + dr["taskname"].ToString() + " " + dr["taskdesc"].ToString() + " 执行完毕----------------------------------------------------------------------");

        }

        /// <summary>
        /// 异步执行任务，测试
        /// </summary>
        /// <param name="taskList"></param>
        public void RunDataSyncTest(List<string> taskList) {

            //获取需要启动的任务
            DataTable dt = GetNeedExecuteTask();
            List<Task> tl = new List<Task>();

            foreach (DataRow dr2 in dt.Rows)
            {//开始循环定时任务
                var tempDt = dt.Clone();
                tempDt.ImportRow(dr2);
                var dr = tempDt.Rows[0];//此处必须要给局部变量赋值

                if (taskList.Contains(dr["scheduledtaskid"].ToString()))//已在任务中
                    continue;

                tl.Add(Task.Factory.StartNew(() =>
                {
                    taskList.Add(dr["scheduledtaskid"].ToString());//添加到list中 

                      //临时表创建 add:wangjh 20240830
                    String apsTempTable = "apstemp" + DateTime.Now.ToString("yyyyMMddHHmmssfffffff");
                    //创建临时表
                    m_LMObj.CreateApsTempTable(apsTempTable);
                    LogHelp.WriteLog("任务：" + dr["taskname"].ToString() + " " + dr["taskdesc"].ToString() + " 临时表创建成功:" + apsTempTable);

                    DealSingleApsTaskTest(dr, apsTempTable);

                    LogHelp.WriteLog("任务id：" + dr["taskname"].ToString() + " " + dr["taskdesc"].ToString() + " 执行完毕----------------------------------------------------------------------");
                    //删除临时表
                    DatabaseHelper.ExecuteSql("drop table " + apsTempTable);
                    LogHelp.WriteLog("任务：" + dr["taskname"].ToString() + " " + dr["taskdesc"].ToString() + " 临时表删除成功:" + apsTempTable);

                    taskList.Remove(dr["scheduledtaskid"].ToString());
                }, TaskCreationOptions.LongRunning));

                //下个定时任务，延迟0.5秒
                Thread.Sleep(500);
            }

           
            //本次产生的task，需要等待完毕
            //Task.WaitAll(tl.ToArray());
        }
        public void RunDataSync(List<string> taskList)
        {
            //获取需要启动的任务
            DataTable dt = GetNeedExecuteTask();
            List<Task> tl = new List<Task>();

            foreach (DataRow dr2 in dt.Rows)
            {//开始循环定时任务
                var tempDt = dt.Clone();
                tempDt.ImportRow(dr2);
                var dr = tempDt.Rows[0];//此处必须要给局部变量赋值

                if (taskList.Count >= maxParallelSync)
                {
                    LogHelp.WriteLog("当前正在执行的任务数为：" + taskList.Count.ToString() + " 已达到最大并行限制----------------------------------------------------------------------");
                    break;
                }
                if (taskList.Contains(dr["scheduledtaskid"].ToString()))//已在任务中
                    continue;

                taskList.Add(dr["scheduledtaskid"].ToString());//添加到list中

                tl.Add(Task.Factory.StartNew(() =>
                {
                    try
                    {   
                        //临时表创建 add:wangjh 20240830
                        String apsTempTable = "apstemp" + DateTime.Now.ToString("yyyyMMddHHmmssfffffff");
                        //创建临时表
                        m_LMObj.CreateApsTempTable(apsTempTable);
                        LogHelp.WriteLog("任务：" + dr["taskname"].ToString() + " " + dr["taskdesc"].ToString() + " 临时表创建成功:" + apsTempTable);

                        DealSingleApsTask(dr, apsTempTable);

                        //删除临时表
                        DatabaseHelper.ExecuteSql("drop table " + apsTempTable);
                        LogHelp.WriteLog("任务：" + dr["taskname"].ToString() + " " + dr["taskdesc"].ToString() + " 临时表删除成功:" + apsTempTable);
                    }
                    catch (Exception ex)
                    {
                        LogHelp.WriteError(dr["taskname"].ToString() + "定时计算异常", ex);
                        CommonHelper.WriteTaskLog(dr["ScheduledTaskId"].ToString(), "3", ex.Message + ex.StackTrace, "1");
                        return;
                    }
                    finally
                    {
                        LogHelp.WriteLog("任务：" + dr["taskname"].ToString() + " " + dr["taskdesc"].ToString() + " 执行完毕，移除队列");
                        taskList.Remove(dr["scheduledtaskid"].ToString());
                    }
                }, TaskCreationOptions.LongRunning));

                //下个定时任务，延迟0.5秒
                Thread.Sleep(500);

            }
            //本次产生的task，需要等待完毕
            //Task.WaitAll(tl.ToArray());
        }

        /// <summary>
        /// 获取需要执行的任务
        /// </summary>
        /// <returns></returns>
        DataTable GetNeedExecuteTask()
        {
            string strSql = @"with temptask as (
select '手动执行中' type,SA.ATTRIBUTEVALUE ISCALPRIORITY,SA2.ATTRIBUTEVALUE APSPOOLID ,SA3.ATTRIBUTEVALUE ISAPSTOEMP,st.scheduledtaskid,st.taskname,st.taskdesc,st.taskstarttime,st.taskendtime,sl.taskexestarttime,st.cycletime,DECODE(SL.TASKEXESTARTTIME,NULL,TO_CHAR(ST.TASKSTARTTIME+ST.CYCLETIME,'YYYY-MM-DD HH24:MI:SS'),TO_CHAR(SL.TASKEXESTARTTIME+ST.CYCLETIME,'YYYY-MM-DD HH24:MI:SS'))
NEXTEXCUTIME2,st.NEXTEXCUTIME from ScheduledTask st 
left join ScheduledTaskLogs sl on st.ScheduledTaskid=sl.ScheduledTaskid and sl.islatest=1
LEFT JOIN SCHEDULEDTASKATTR SA ON SA.SCHEDULEDTASKID=ST.SCHEDULEDTASKID AND SA.ISUSE=0 AND SA.ATTRIBUTENAME=ST.tasktype||'重算优先级'
LEFT JOIN SCHEDULEDTASKATTR SA2 ON SA2.SCHEDULEDTASKID=ST.SCHEDULEDTASKID AND SA2.ISUSE=0 AND SA2.ATTRIBUTENAME=ST.tasktype||'排产池'
LEFT JOIN SCHEDULEDTASKATTR SA3 ON SA3.SCHEDULEDTASKID=ST.SCHEDULEDTASKID AND SA3.ISUSE=0 AND SA3.ATTRIBUTENAME=ST.TASKTYPE||'排到人'
where st.tasktype = 1 and st.isuse=0 and st.status!=3 and sl.executetype=2 and sl.taskexeendtime is null
) 
select * from temptask
union all
select '自动执行中' type,SA.ATTRIBUTEVALUE ISCALPRIORITY,SA2.ATTRIBUTEVALUE APSPOOLID ,SA3.ATTRIBUTEVALUE ISAPSTOEMP,st.scheduledtaskid,st.taskname,st.taskdesc,st.taskstarttime,st.taskendtime,sl.taskexestarttime,st.cycletime,DECODE(SL.TASKEXESTARTTIME,NULL,TO_CHAR(ST.TASKSTARTTIME+ST.CYCLETIME,'YYYY-MM-DD HH24:MI:SS'),TO_CHAR(SL.TASKEXESTARTTIME+ST.CYCLETIME,'YYYY-MM-DD HH24:MI:SS'))
NEXTEXCUTIME2,st.NEXTEXCUTIME from ScheduledTask st 
left join ScheduledTaskLogs sl on st.ScheduledTaskid=sl.ScheduledTaskid and sl.islatest=1
LEFT JOIN SCHEDULEDTASKATTR SA ON SA.SCHEDULEDTASKID=ST.SCHEDULEDTASKID AND SA.ISUSE=0 AND SA.ATTRIBUTENAME=ST.tasktype||'重算优先级'
LEFT JOIN SCHEDULEDTASKATTR SA2 ON SA2.SCHEDULEDTASKID=ST.SCHEDULEDTASKID AND SA2.ISUSE=0 AND SA2.ATTRIBUTENAME=ST.tasktype||'排产池'
LEFT JOIN SCHEDULEDTASKATTR SA3 ON SA3.SCHEDULEDTASKID=ST.SCHEDULEDTASKID AND SA3.ISUSE=0 AND SA3.ATTRIBUTENAME=ST.TASKTYPE||'排到人'
where st.tasktype = 1 and st.isuse=0 and st.status!=3 and sl.executetype=1 and sl.taskexeendtime is null
union all
select '自动未执行' type,SA.ATTRIBUTEVALUE ISCALPRIORITY,SA2.ATTRIBUTEVALUE APSPOOLID,SA3.ATTRIBUTEVALUE ISAPSTOEMP,st.scheduledtaskid,st.taskname,st.taskdesc,st.taskstarttime,st.taskendtime,null taskexestarttime,st.cycletime,DECODE(SL.TASKEXESTARTTIME,NULL,TO_CHAR(ST.TASKSTARTTIME+ST.CYCLETIME,'YYYY-MM-DD HH24:MI:SS'),TO_CHAR(SL.TASKEXESTARTTIME+ST.CYCLETIME,'YYYY-MM-DD HH24:MI:SS'))
NEXTEXCUTIME2,st.NEXTEXCUTIME from ScheduledTask st
left join ScheduledTaskLogs sl on st.ScheduledTaskid=sl.ScheduledTaskid and sl.islatest=1
LEFT JOIN SCHEDULEDTASKATTR SA ON SA.SCHEDULEDTASKID=ST.SCHEDULEDTASKID AND SA.ISUSE=0 AND SA.ATTRIBUTENAME=ST.tasktype||'重算优先级'
LEFT JOIN SCHEDULEDTASKATTR SA2 ON SA2.SCHEDULEDTASKID=ST.SCHEDULEDTASKID AND SA2.ISUSE=0 AND SA2.ATTRIBUTENAME=ST.tasktype||'排产池'
LEFT JOIN SCHEDULEDTASKATTR SA3 ON SA3.SCHEDULEDTASKID=ST.SCHEDULEDTASKID AND SA3.ISUSE=0 AND SA3.ATTRIBUTENAME=ST.TASKTYPE||'排到人'
where st.tasktype = 1 and st.isuse=0 and st.status!=3 and not exists (select 1 from ScheduledTaskLogs sl where sl.scheduledtaskid=st.scheduledtaskid and sl.islatest=1 and sl.taskexeendtime is null)
and not exists (select 1 from temptask tt where tt.scheduledtaskid=st.scheduledtaskid )";

            DataTable dt = DatabaseHelper.Query_ReturnDatTable(strSql);
            //筛选出有效需要执行的任务
            var re = dt.AsEnumerable().Where((dr) =>
            {
                if (dr["type"].ToString() == "自动未执行")
                {
                    if (DateTime.Parse(dr["NEXTEXCUTIME"].ToString()) > DateTime.Parse(dr["taskendtime"].ToString())) //下次执行时间大于任务指定结束时间，不执行
                    {
                        return false;
                    }
                    if (DateTime.Parse(dr["NEXTEXCUTIME"].ToString()) > DateTime.Now)//下次执行时间大于当前时间，不执行
                    {
                        return false;
                    }

                }
                return true;
            });
            if (re.Count() > 0)
                return re.CopyToDataTable();
            else
                return dt.Clone();
        }

        /// <summary>
        /// 单个任务执行
        /// </summary>
        void DealSingleApsTask(DataRow dr, String apsTempTable)
        {
            if (dr["type"].ToString() == "自动未执行")
            {
                CommonHelper.WriteTaskLog(dr["ScheduledTaskId"].ToString(), "2", "", "1");//开始执行
                LogHelp.WriteLog("任务：" + dr["taskname"].ToString() + " " + dr["taskdesc"].ToString() + " 开始执行----------------------------------------------------------------------");
            }
            string apspoolID = dr["APSPOOLID"].ToString();
            string isCalpriority = dr["ISCALPRIORITY"].ToString();
            string isApstoEmp = dr["ISAPSTOEMP"].ToString();
            var taskMsg = "";
            //开始启动这次任务
            var sqlList = new ArrayList();
            DataTable containerDt = m_LMObj.GetApsPoolContainerInfo(new Dictionary<string, string>() { { "PoolID", apspoolID } }).DBTable;
            //记录计算的总工序数，总设备数，总提前截止批次数 add:wangjh 20250626
            int totalCalStepCount = 0; int totalCalResCount = 0; int totalDeadlineCount = 0;

            if (containerDt.Rows.Count == 0)
            {
                goto end;
            }

            //重新计算优先级
            if (isCalpriority == "1")
            {
                LogHelp.WriteLog("任务：" + dr["taskname"].ToString() + " " + dr["taskdesc"].ToString() + " 开始计算优先级,批次个数：" + containerDt.Rows.Count.ToString() + "----------------------------------------------------------------------");
                string msg = m_LMObj.calcContainerApsPriority(containerDt);
                if (msg != "")
                {
                    taskMsg += msg + " ";
                }
                LogHelp.WriteLog("任务：" + dr["taskname"].ToString() + " " + dr["taskdesc"].ToString() + " 完成计算优先级----------------------------------------------------------------------" + msg);
            }

            CommonHelper.UpdateTaskLogStartDate(dr["ScheduledTaskId"].ToString());//更新定时任务日志的开始时间为当前时间 add by zhangrj 20240328

            //排产前处理
            containerDt = m_LMObj.GetApsPoolContainerInfo(new Dictionary<string, string>() { { "PoolID", apspoolID } }).DBTable;//重新查询一遍
            var ApsLmCalculateDt = containerDt.DefaultView.ToTable(true, "apspoolid", "ISSUBCON", "containerid", "containername", "workflowid", "ENDTIME",
                "CONTAINERTYPE", "TOGETHERFLAG", "BEGINSEQUENCE", "EXPECTMATERIALDATE", "REALSTARTDATE","workcenterName");
            ApsLmCalculateDt.Columns.AddRange(new DataColumn[] { new DataColumn("STARTTIME"), new DataColumn("DJDKSPECIAL") });
            var ApsLmCalculateDt2 = ApsLmCalculateDt.AsEnumerable().Select((DataRow row) =>
            {
                row["STARTTIME"] = string.IsNullOrWhiteSpace(row["EXPECTMATERIALDATE"].ToString()) ? row["REALSTARTDATE"] : row["EXPECTMATERIALDATE"];
                row["DJDKSPECIAL"] = 2;
                return row;
            }).CopyToDataTable();
            var faConDt = ApsLmCalculateDt2.Select("ISSUBCON is null").CopyToDataTable();//主卡    
            if (ApsLmCalculateDt2.Select("ISSUBCON='1'").Length > 0)//子卡
            {
                faConDt.Merge(ApsLmCalculateDt2.Select("ISSUBCON='1'").CopyToDataTable());
            }
            //开始排产计算
            Dictionary<string, string> para = new Dictionary<string, string>();
            para["EmployeeID"] = "";//排产人暂时置空
            para["IsApsToEmp"] = isApstoEmp;//是否排到人
            var ApsOccupyConIdList = new List<string>();

            int num = 0;
            foreach (DataRow conRow in faConDt.Rows)
            {
                num++;
                //检查是否提前终止
                if (DatabaseHelper.GetSingle(string.Format(@"select 1 from ScheduledTaskLogs sl
                            where sl.scheduledtaskid='{0}' and sl.islatest=1 and sl.taskexeendtime is not null", dr["ScheduledTaskId"].ToString())) != null)
                {
                    LogHelp.WriteLog("任务：" + dr["taskname"].ToString() + " " + dr["taskdesc"].ToString() + " 执行完毕----------------------------------------------------------------------");
                    return;
                }
                //
                //LogHelp.WriteLog("任务：" + dr["taskname"].ToString() + " 的批次：" + conRow["containername"].ToString()+" 开始计算排产");
                try {
                    var apsConDt = conRow.Table.Clone();
                    apsConDt.ImportRow(conRow);
                    var result = m_LMObj.LMPositiveCalculate(apsConDt, para, false, ApsOccupyConIdList, apsTempTable);

                    if (result.Result)//排产成功
                    {
                        if (!ApsOccupyConIdList.Contains(conRow["containerid"].ToString()))
                        {
                            ApsOccupyConIdList.Add(conRow["containerid"].ToString());
                        }
                    }
                    if (!string.IsNullOrWhiteSpace(result.Message))
                    {
                        //此批次排产有特殊消息，记录日志，放在排产的代码里了
                        //WriteContainerLog(dr["ScheduledTaskId"].ToString(), conRow["containerid"].ToString(), conRow["containername"].ToString(), result.Message, 1);                    
                    }
                     //add:wangjh 20250626 增加记录日志
                     if (result.ReturnData != null) {
                         Dictionary<string, object> returnData = (Dictionary<string, object>)result.ReturnData;
                         result.Message += ",计算工序数：" + returnData["calStepCount"].ToString() + ",计算设备数：" + returnData["calResCount"].ToString();
                         totalCalStepCount += int.Parse(returnData["calStepCount"].ToString());
                         totalCalResCount += int.Parse(returnData["calResCount"].ToString());
                         if (Convert.ToBoolean ( returnData["isDeadline"]))
                         {
                             totalDeadlineCount += 1;
                         }
                     }
                     LogHelp.WriteLog("任务：" + dr["taskname"].ToString() + " " + dr["taskdesc"].ToString() + " 的批次：第：" + num.ToString() + "个 " + conRow["containername"].ToString() + " 排产计算完毕 " + result.Message);
                 
                }
                catch (Exception ex)
                {
                    LogHelp.WriteLog("任务：" + dr["taskname"].ToString() + " " + dr["taskdesc"].ToString() + " 的批次：第：" + num.ToString() + "个 " + conRow["containername"].ToString() + " 排产计算错误 " + ex.Message);                
                }
                
            }
        end:
            //此任务执行完毕
            CommonHelper.WriteTaskLog(dr["ScheduledTaskId"].ToString(), "4", " 任务执行完毕，批次数：" + containerDt.Rows.Count.ToString() +
            "计算的总工序数：" + totalCalStepCount.ToString() +
            "计算的总设备数：" + totalCalResCount.ToString() +
            "提前截止批次数:" + totalDeadlineCount.ToString()
            , "1");
            LogHelp.WriteLog("任务：" + dr["taskname"].ToString() + " " + dr["taskdesc"].ToString() + " 执行完毕,批次数：" + containerDt.Rows.Count.ToString() +
            "计算的总工序数：" + totalCalStepCount.ToString() +
            "计算的总设备数：" + totalCalResCount.ToString() +
            "提前截止批次数:" + totalDeadlineCount.ToString() +
            "----------------------------------------------------------------------");

        }
    }
}
